package com.frank.oj.service.admin.system.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.text.UnicodeUtil;
import cn.hutool.json.JSONObject;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.exception.NacosException;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.frank.model.entity.common.File;
import com.frank.model.entity.judge.RemoteJudgeAccount;
import com.frank.oj.common.exception.StatusFailException;
import com.frank.oj.common.result.CommonResult;
import com.frank.oj.config.NacosSwitchConfig;
import com.frank.oj.config.SwitchConfig;
import com.frank.oj.config.WebConfig;
import com.frank.oj.constant.Constants;
import com.frank.oj.manager.ConfigManager;
import com.frank.oj.model.dto.*;
import com.frank.oj.model.vo.ConfigVO;
import com.frank.oj.service.admin.system.ConfigService;
import com.frank.oj.service.entity.common.FileEntityService;
import com.frank.oj.service.entity.judge.RemoteJudgeAccountEntityService;
import com.frank.oj.utils.ConfigUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

/**
 * @author frank
 * @Date 2024/3/27
 */
@Service
@Slf4j
public class ConfigServiceImpl implements ConfigService {
    @Resource
    private ConfigManager configManager;
    @Resource
    private NacosSwitchConfig nacosSwitchConfig;
    @Resource
    private ConfigVO configVO;
    @Resource
    private FileEntityService fileEntityService;
    @Resource
    private ConfigUtils configUtils;
    @Resource
    private RemoteJudgeAccountEntityService remoteJudgeAccountEntityService;

    @Override
    public CommonResult<JSONObject> getServiceInfo() {
        return CommonResult.successResponse(configManager.getServiceInfo());
    }

    @Override
    public CommonResult<List<JSONObject>> getJudgeServiceInfo() {
        return CommonResult.successResponse(configManager.getJudgeServerInfo());
    }

    @Override
    public WebConfigDTO getWebConfig() {
        WebConfig webConfig = nacosSwitchConfig.getWebConfig();
        return WebConfigDTO.builder()
                .baseUrl(UnicodeUtil.toString(webConfig.getBaseUrl()))
                .description(UnicodeUtil.toString(webConfig.getDescription()))
                .register(webConfig.getRegister())
                .recordName(UnicodeUtil.toString(webConfig.getRecordName()))
                .recordUrl(UnicodeUtil.toString(webConfig.getRecordUrl()))
                .build();
    }

    @Override
    public EmailConfigDTO getEmailConfig() {
        WebConfig webConfig = nacosSwitchConfig.getWebConfig();
        return EmailConfigDTO.builder()
                .emailUsername(webConfig.getEmailUsername())
                .emailPassword(webConfig.getEmailPassword())
                .emailHost(webConfig.getEmailHost())
                .emailPort(webConfig.getEmailPort())
                .emailBGImg(webConfig.getEmailBGImg())
                .emailSsl(webConfig.getEmailSsl())
                .build();
    }

    @Override
    public DBAndRedisConfigDTO getDBAndRedisConfig() {
        return DBAndRedisConfigDTO.builder()
                .dbName(configVO.getMysqlDBName())
                .dbHost(configVO.getMysqlHost())
                .dbPort(configVO.getMysqlPort())
                .dbUsername(configVO.getMysqlUsername())
                .dbPassword(configVO.getMysqlPassword())
                .redisHost(configVO.getRedisHost())
                .redisPort(configVO.getRedisPort())
                .redisPassword(configVO.getRedisPassword())
                .build();
    }

    @Override
    public void deleteHomeCarousel(Long id) throws StatusFailException {
        File file = fileEntityService.getById(id);
        if (file == null) {
            throw new StatusFailException("图片不存在");
        }
        boolean remove = fileEntityService.removeById(id);
        if (remove) {
            FileUtil.del(file.getFilePath());
        } else {
            throw new StatusFailException("删除失败，请稍后重试！");
        }
    }

    @Override
    public void setWebConfig(WebConfigDTO config) throws StatusFailException {
        WebConfig webConfig = nacosSwitchConfig.getWebConfig();

        if (!StringUtils.isEmpty(config.getBaseUrl())) {
            webConfig.setBaseUrl(config.getBaseUrl());
        }
        if (!StringUtils.isEmpty(config.getDescription())) {
            webConfig.setDescription(config.getDescription());
        }
        if (config.getRegister() != null) {
            webConfig.setRegister(config.getRegister());
        }
        if (!StringUtils.isEmpty(config.getRecordName())) {
            webConfig.setRecordName(config.getRecordName());
        }
        if (!StringUtils.isEmpty(config.getRecordUrl())) {
            webConfig.setRecordUrl(config.getRecordUrl());
        }

        boolean isOk = nacosSwitchConfig.publishWebConfig();
        if (!isOk) {
            throw new StatusFailException("基础信息修改失败");
        }
    }

    @Override
    public void setEmailConfig(EmailConfigDTO config) throws StatusFailException {
        WebConfig webConfig = nacosSwitchConfig.getWebConfig();
        if (!StringUtils.isEmpty(config.getEmailHost())) {
            webConfig.setEmailHost(config.getEmailHost());
        }
        if (!StringUtils.isEmpty(config.getEmailPassword())) {
            webConfig.setEmailPassword(config.getEmailPassword());
        }

        if (config.getEmailPort() != null) {
            webConfig.setEmailPort(config.getEmailPort());
        }

        if (!StringUtils.isEmpty(config.getEmailUsername())) {
            webConfig.setEmailUsername(config.getEmailUsername());
        }

        if (!StringUtils.isEmpty(config.getEmailBGImg())) {
            webConfig.setEmailBGImg(config.getEmailBGImg());
        }

        if (config.getEmailSsl() != null) {
            webConfig.setEmailSsl(config.getEmailSsl());
        }

        boolean isOk = nacosSwitchConfig.publishWebConfig();
        if (!isOk) {
            throw new StatusFailException("邮箱修改失败");
        }
    }

    @Override
    public void setDBAndRedisConfig(DBAndRedisConfigDTO config) throws StatusFailException {
        if (!StringUtils.isEmpty(config.getDbName())) {
            configVO.setMysqlDBName(config.getDbName());
        }
        if (!StringUtils.isEmpty(config.getDbHost())) {
            configVO.setMysqlHost(config.getDbHost());
        }
        if (config.getDbPort() != null) {
            configVO.setMysqlPort(config.getDbPort());
        }
        if (!StringUtils.isEmpty(config.getDbUsername())) {
            configVO.setMysqlUsername(config.getDbUsername());
        }
        if (!StringUtils.isEmpty(config.getDbPassword())) {
            configVO.setMysqlPassword(config.getDbPassword());
        }

        if (!StringUtils.isEmpty(config.getRedisHost())) {
            configVO.setRedisHost(config.getRedisHost());
        }

        if (config.getRedisPort() != null) {
            configVO.setRedisPort(config.getRedisPort());
        }
        if (!StringUtils.isEmpty(config.getRedisPassword())) {
            configVO.setRedisPassword(config.getRedisPassword());
        }

        boolean isOk = configManager.sendNewConfigToNacos();

        if (!isOk) {
            throw new StatusFailException("修改失败");
        }
    }

    @Override
    public SwitchConfigDTO getSwitchConfig() {
        SwitchConfig switchConfig = nacosSwitchConfig.getSwitchConfig();
        SwitchConfigDTO switchConfigDTO = new SwitchConfigDTO();
        BeanUtil.copyProperties(switchConfig, switchConfigDTO);

        return switchConfigDTO;
    }

    @Override
    public void setSwitchConfig(SwitchConfigDTO configDTO) throws StatusFailException {

        SwitchConfig switchConfig = nacosSwitchConfig.getSwitchConfig();

        if (configDTO.getOpenPublicDiscussion() != null) {
            switchConfig.setOpenPublicDiscussion(configDTO.getOpenPublicDiscussion());
        }
        if (configDTO.getOpenGroupDiscussion() != null) {
            switchConfig.setOpenGroupDiscussion(configDTO.getOpenGroupDiscussion());
        }
        if (configDTO.getOpenContestComment() != null) {
            switchConfig.setOpenContestComment(configDTO.getOpenContestComment());
        }
        if (configDTO.getOpenPublicJudge() != null) {
            switchConfig.setOpenPublicJudge(configDTO.getOpenPublicJudge());
        }
        if (configDTO.getOpenGroupJudge() != null) {
            switchConfig.setOpenGroupJudge(configDTO.getOpenGroupJudge());
        }
        if (configDTO.getOpenContestJudge() != null) {
            switchConfig.setOpenContestJudge(configDTO.getOpenContestJudge());
        }

        if (configDTO.getHideNonContestSubmissionCode() != null) {
            switchConfig.setHideNonContestSubmissionCode(configDTO.getHideNonContestSubmissionCode());
        }

        if (configDTO.getDefaultCreateDiscussionACInitValue() != null) {
            switchConfig.setDefaultCreateDiscussionACInitValue(configDTO.getDefaultCreateDiscussionACInitValue());
        }

        if (configDTO.getDefaultCreateDiscussionDailyLimit() != null) {
            switchConfig.setDefaultCreateDiscussionDailyLimit(configDTO.getDefaultCreateDiscussionDailyLimit());
        }

        if (configDTO.getDefaultCreateCommentACInitValue() != null) {
            switchConfig.setDefaultCreateCommentACInitValue(configDTO.getDefaultCreateCommentACInitValue());
        }

        // 提交间隔
        if (configDTO.getDefaultSubmitInterval() != null) {
            if (configDTO.getDefaultSubmitInterval() >= 0) {
                switchConfig.setDefaultSubmitInterval(configDTO.getDefaultSubmitInterval());
            } else {
                switchConfig.setDefaultSubmitInterval(0);
            }
        }

        // 团队
        if (configDTO.getDefaultCreateGroupACInitValue() != null) {
            switchConfig.setDefaultCreateGroupACInitValue(configDTO.getDefaultCreateGroupACInitValue());
        }

        if (configDTO.getDefaultCreateGroupDailyLimit() != null) {
            switchConfig.setDefaultCreateGroupDailyLimit(configDTO.getDefaultCreateGroupDailyLimit());
        }
        if (configDTO.getDefaultCreateGroupLimit() != null) {
            switchConfig.setDefaultCreateGroupLimit(configDTO.getDefaultCreateGroupLimit());
        }

        if (checkListDiff(configDTO.getCfUsernameList(), switchConfig.getCfUsernameList()) ||
                checkListDiff(configDTO.getCfPasswordList(), switchConfig.getCfPasswordList())) {
            switchConfig.setCfUsernameList(configDTO.getCfUsernameList());
            switchConfig.setCfPasswordList(configDTO.getCfPasswordList());

            changeRemoteJudgeAccount(configDTO.getCfUsernameList(), configDTO.getCfPasswordList(),
                    Constants.RemoteOJ.CODEFORCES.getName());
        }
        if (checkListDiff(configDTO.getHduUsernameList(), switchConfig.getHduUsernameList()) ||
                checkListDiff(configDTO.getHduPasswordList(), switchConfig.getHduPasswordList())) {
            switchConfig.setHduUsernameList(configDTO.getHduUsernameList());
            switchConfig.setHduPasswordList(configDTO.getHduPasswordList());

            changeRemoteJudgeAccount(configDTO.getHduUsernameList(), configDTO.getHduPasswordList(),
                    Constants.RemoteOJ.HDU.getName());
        }

        if (checkListDiff(configDTO.getPojUsernameList(), switchConfig.getPojUsernameList()) ||
                checkListDiff(configDTO.getPojPasswordList(), switchConfig.getPojPasswordList())) {
            switchConfig.setCfUsernameList(configDTO.getPojUsernameList());
            switchConfig.setCfPasswordList(configDTO.getPojPasswordList());

            changeRemoteJudgeAccount(configDTO.getPojUsernameList(), configDTO.getPojPasswordList(),
                    Constants.RemoteOJ.POJ.getName());
        }
        if (checkListDiff(configDTO.getSpojUsernameList(), switchConfig.getSpojUsernameList()) ||
                checkListDiff(configDTO.getSpojPasswordList(), switchConfig.getSpojPasswordList())) {
            switchConfig.setCfUsernameList(configDTO.getSpojUsernameList());
            switchConfig.setCfPasswordList(configDTO.getSpojPasswordList());

            changeRemoteJudgeAccount(configDTO.getSpojUsernameList(), configDTO.getSpojPasswordList(),
                    Constants.RemoteOJ.SPOJ.getName());
        }
        if (checkListDiff(configDTO.getAtcoderUsernameList(), switchConfig.getAtcoderUsernameList()) ||
                checkListDiff(configDTO.getAtcoderPasswordList(), switchConfig.getAtcoderPasswordList())) {
            switchConfig.setCfUsernameList(configDTO.getAtcoderUsernameList());
            switchConfig.setCfPasswordList(configDTO.getAtcoderPasswordList());

            changeRemoteJudgeAccount(configDTO.getAtcoderUsernameList(), configDTO.getAtcoderPasswordList(),
                    Constants.RemoteOJ.ATCODER.getName());
        }

        boolean isOk = nacosSwitchConfig.publishSwitchConfig();
        if (!isOk) {
            throw new StatusFailException("账号配置修改失败");
        }
    }

    @Override
    public CommonResult<Void> testEmail(TestEmailDTO testEmailDto) {
        try {
            configManager.testEmail(testEmailDto);
            return CommonResult.successResponse();
        } catch (StatusFailException e) {
            return CommonResult.errorResponse(e.getMessage());
        }
    }

    private void changeRemoteJudgeAccount(List<String> usernameList, List<String> passwordList, String oj) {
        if (CollectionUtils.isEmpty(usernameList) || CollectionUtils.isEmpty(passwordList) || usernameList.size() != passwordList.size()) {
            log.error("HC：远程判题账号为空或存在异常");
        }

        LambdaQueryWrapper<RemoteJudgeAccount> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(RemoteJudgeAccount::getOj, oj);
        remoteJudgeAccountEntityService.remove(queryWrapper);

        List<RemoteJudgeAccount> newCounts = new ArrayList<>();

        for (int i = 0; i < usernameList.size(); i++) {
            newCounts.add(new RemoteJudgeAccount()
                    .setUsername(usernameList.get(i))
                    .setPassword(passwordList.get(i))
                    .setStatus(true)
                    .setVersion(0L)
                    .setOj(oj));
        }

        if (!newCounts.isEmpty()) {
            boolean isOk = remoteJudgeAccountEntityService.saveOrUpdateBatch(newCounts);
            if (!isOk) {
                log.error("HC：远程判题账号修改失败");
            }
        }
    }

    private boolean checkListDiff(List<String> list1, List<String> list2) {
        if (list1.size() != list2.size()) {
            return true;
        }
        return !list1.toString().equals(list2.toString());
    }


}
